#ifndef GX_STREAM_H
#define GX_STREAM_H

#include "Basic/GxString.h"
#include "Basic/Array.hpp"
#include "stdio.h"

namespace GxLibBasic
{
	const int gxteANSI  = 0;				// ansi
	const int gxteUTF8 = 1;					// utf-8
	const int gxteUTF16 = 2;				// utf-16 little endian
	const int gxteUTF16_BigEndian = 3;		// utf-16 big endian
	int GetTextEncoding(String FileName); 

	enum gxFileStreamMode
	{
		gxfmRead,
		gxfmWrite,
		gxfmAppend,
		gxfmReadWithWrite,
		gxfmWriteWithRead
	};

	enum gxFileShareMode
	{
		gxfmDenyNo,
		gxfmDenyRead,
		gxfmDenyWrite,
		gxfmDenyReadWrite
	};

	enum gxSeekOrigin
	{
		gxsoCurrent,
		gxsoBegin,
		gxsoEnd
	};

	class Stream : public Object
	{
	public:
		virtual void Seek(gxSeekOrigin origin, Int Offset) =0;
		virtual Int GetPosition()const = 0;
		virtual void SetPosition(Int Pos) = 0;
		virtual Int ReadBuffer(void *buf, Int element_size, Int count)=0;
		virtual Int WriteBuffer(const void *buf, Int element_size, Int count)=0;
		template <typename T>
		Int ReadBuffer(T *buf, Int count)
		{
			return ReadBuffer(buf, sizeof(T), count);
		};
		template <typename T>
		Int WriteBuffer(const T *buf, Int count)
		{
			return WriteBuffer(buf, sizeof(T), count);
		};
		virtual void CopyFrom(Stream * s);
		virtual Int Size()const=0 ;
		virtual bool IsEnd()const=0 ;
	};

	class FileStream : public Stream
	{
	protected:
		int FTextEncoding;
		FILE *FHandle;
	public:
		FileStream(String FileName, gxFileStreamMode mode = gxfmReadWithWrite, gxFileShareMode = gxfmDenyNo, bool Text = false, int Encoding = gxteUTF16);
		~FileStream();
	public:
		virtual void Seek(gxSeekOrigin origin, Int Offset);
		virtual Int GetPosition() const;
		virtual void SetPosition(Int Pos);
		template <typename T>
		Int ReadBuffer(T *buf, Int count)
		{
			return fread_s(buf,count * sizeof(T), sizeof(T), count, FHandle);
		};
		template <typename T>
		Int WriteBuffer(const T *buf, Int count)
		{
			return (int)fwrite(buf,sizeof(T),count,FHandle);
		};
		virtual Int ReadBuffer(void *buf, Int element_size, Int count);
		virtual Int WriteBuffer(const void *buf, Int element_size, Int count);
		virtual Int Size() const;
		virtual bool IsEnd() const;
	};

	class MemoryStream : public Stream
	{
	protected:
		Array<char> FBuf;
		Int FPtr;
	public:
		MemoryStream(const char * buf, int len);
		MemoryStream();
		virtual Int GetPosition()const;
		virtual void SetPosition(Int Pos);
		virtual void Seek(gxSeekOrigin origin, Int Offset);
		virtual Int Size()const;
		virtual Int ReadBuffer(void *buf, Int element_size, Int count);
		virtual Int WriteBuffer(const void *buf, Int element_size, Int count);
		virtual bool IsEnd()const;
		char * Buffer();
	};

	class TextStream
	{
	public:
		virtual wchar_t ReadChar() =0;
		virtual void WriteChar(wchar_t c) = 0;
		virtual String GetLine() =0;
		virtual void WriteString(String s) = 0;
	};

	class TextFileStream : public FileStream, public TextStream
	{
	public:
		TextFileStream(String FileName, gxFileStreamMode mode = gxfmReadWithWrite,
			gxFileShareMode share = gxfmDenyNo, int Encoding = gxteUTF16);
	public:
		wchar_t ReadChar();
		void WriteChar(wchar_t c);
		String GetLine();
		void WriteString(String s);
		
	};

	String ReadTextFile(const String & fileName);
	void WriteTextFile(const String & fileName, const String & text);

	class TextMemoryStream : public TextStream
	{
	protected:
		String	FBuf;
		Int		Position;
	public:
		TextMemoryStream();
		TextMemoryStream(String str);
	public:
		void Seek(gxSeekOrigin origin, Int Offset);
		Int GetPosition();
		void SetPosition(Int Pos);
		Int ReadBuffer(void *buf, Int size);
		Int WriteBuffer(const void *buf, Int size);

		wchar_t ReadChar();
		void WriteChar(wchar_t c);
		String GetLine();
		void WriteString(String s);
		void CopyFrom(const Stream * s);
		Int Size();
	};
}
#endif